#include "sceneGraph.h"

vector<sceneNode>* sceneGraph::getFrames()
{
	return &frames;
}

sceneGraph::sceneGraph()
{
	//camera = new sceneCamera();	//create camera

	//create root
	sceneNode root("root");
	frames.push_back(root);

}

int sceneGraph::getIndex(string n)
{
	for(int i=0; i<(int)frames.size(); i++)
	{
		if(n == frames[i].getName()) return i;
	}
	return -1;
}

sceneNode* sceneGraph::addFrame(sceneNode f)
{
	frames.push_back(f);
	return &frames[frames.size()-1];
}

sceneNode* sceneGraph::createFrame(string n)
{
	sceneNode newFrame(n);
	frames.push_back(newFrame);
	return &frames[frames.size()-1];
}
sceneNode* sceneGraph::getFrame(int n)				//returns frame at the given index
{
	return &frames[n];
}

sceneNode* sceneGraph::getFrame(string n)				//returns frame at the given index
{
	for(int i=0; i<(int)frames.size(); i++)
		if (frames[i].getName() == n) return &frames[i];
	return NULL;
}

sceneNode* sceneGraph::getScene()					//returns frame with index 0
{
	return &frames[0];
}

sceneNode* sceneGraph::getParent(sceneNode* f)		//returns parent of the referenced frame
{
	for(int i=0; i<(int)frames.size(); i++)
		if (frames[i].isChild(f->getName())) return &frames[i];
	return NULL;
}

sceneNode* sceneGraph::getParent(int n)
{
	for(int i=0; i<(int)frames.size(); i++)
		if (frames[i].isChild(frames[n].getName())) return &frames[i];
	return NULL;
}

void sceneGraph::assignToRoot(string n)
{
	//sceneNode* c;
	/*
	for(int i=0; i<(int)frames.size(); i++)
		if (frames[i].getName() == n) c = &frames[i];
		*/
	frames[0].addChild(n);
}

void sceneGraph::removeFrame(int i)
{
	frames.erase(frames.begin()+i);
	cleanup();
}

/*
void sceneGraph::removeFrame(sceneNode* f)
{
	frames.erase(frames.begin()+getIndex(f));
	cleanup();
}
*/
void sceneGraph::removeFrame(string n)
{
	for(int i=0; i<(int)frames.size(); i++)
		if (frames[i].getName() == n) frames.erase(frames.begin()+i);
	cleanup();
}

void sceneGraph::clear()
{
	frames.clear();
	sceneNode root("root");
	frames.push_back(root);
	/*
	if((int)frames.size() > 1)
		frames.erase(frames.begin()+1, frames.end());
	cleanup();
	*/
}

bool sceneGraph::exists(string n)
{
	int num = (int)frames.size();
	for(int i=1; i<num; i++)		//search every node
		if (frames[i].getName() == n) return true;
	return false;
}

void sceneGraph::setCornellSize()
{
	if(exists("cornell"))
	{
		float s;
		D3DXVECTOR3 pos;
		s = D3DXVec3Length(&getCamera()->getPos());
		s *= 2;


		D3DXMATRIX temp;
		D3DXMatrixScaling(&temp, s,s,s);

		getFrame("cornell")->setMatrix(temp);
	}
}



void sceneGraph::cleanup()
{
	int* countArr;
	int num = (int)frames.size();
	countArr = new int[num];		//pirate counting!


	for(int i=0; i<num; i++)		//initialiaze values
	{
		countArr[i] = 0;
	}

	for(int i=0; i<num; i++)		//search every node
	{
		if(frames[i].childCount() > 0)	//that has children
		{
			for(int j=0; j<frames[i].childCount(); j++)	//count each child
			{
				if (exists(frames[i].getChildren()->at(j)))
				{
					int index = getIndex(frames[i].getChildren()->at(j));
					countArr[index]++;
				}
				else
				{
					frames[i].getChildren()->erase(frames[i].getChildren()->begin()+j);
					j--;
				}

			}
		}
	}

	//delete parentless
	for(int i=num-1; i>0; i--)
	{
		if(countArr[i]==0) frames.erase(frames.begin()+i);
	}

}
				

void sceneGraph::addLight(sceneLight l)
{
	lights.push_back(l);
}

sceneLight* sceneGraph::getLight(string name)
{
	for(int i=0; i<(int)lights.size(); i++)
		if (lights[i].getName() == name) return &lights[i];
	return NULL;
}

void sceneGraph::removeLight(string name)
{
	for(int i=0; i<(int)lights.size(); i++)
		if (lights[i].getName() == name) lights.erase(lights.begin()+i);
}

/*
sceneLight* getLight(int n)
{
	return &lights[n];

}
*/

void sceneGraph::drawFrame(	sceneNode* tFrame,
							D3DXMATRIX parentMatrix,
							ID3D10EffectMatrixVariable* pWorldMatrixEffectVariable,
							ID3D10EffectMatrixVariable* pWorldMatrixITVariable,
							ID3D10EffectTechnique* pBasicTechnique,
							D3D10_TECHNIQUE_DESC techDesc)
{
	D3DXMATRIX tempMatrix = tFrame->getMatrix()*parentMatrix;

	pWorldMatrixEffectVariable->SetMatrix(tempMatrix);
	D3DXMATRIX matWorldIT;
	D3DXMatrixInverse( &matWorldIT, NULL, &tempMatrix );
	D3DXMatrixTranspose( &matWorldIT, &matWorldIT );
	pWorldMatrixITVariable->SetMatrix(matWorldIT);

	if (tFrame->getName() != "root" && !(tFrame->getName() == "cornell" && techDesc.Name == "Shadow01")) {
		for( UINT p = 0; p < techDesc.Passes; p++ )
		{
			//apply technique
			pBasicTechnique->GetPassByIndex( 0 )->Apply( 0 );
			tFrame->getMesh()->DrawSubset(0);
		}
	}
	
	int num = tFrame->childCount();
	if(num > 0)
		for(int i=0; i<num; i++)
			drawFrame(	getFrame(tFrame->getChildren()->at(i)),
						tempMatrix,
						pWorldMatrixEffectVariable,
						pWorldMatrixITVariable,
						pBasicTechnique,
						techDesc);

}

void sceneGraph::draw(	ID3D10EffectMatrixVariable* pWorldMatrixEffectVariable,
						ID3D10EffectMatrixVariable* pWorldMatrixITVariable,
						ID3D10EffectTechnique* pBasicTechnique,
						D3D10_TECHNIQUE_DESC techDesc)
{
	D3DXMATRIX tempMatrix;
	D3DXMatrixIdentity(&tempMatrix);

	drawFrame(	getScene(),
				tempMatrix,
				pWorldMatrixEffectVariable,
				pWorldMatrixITVariable,
				pBasicTechnique,
				techDesc);
}


//camera methods
sceneCamera* sceneGraph::getCamera()
{
	return &camera;
}